package com.xunqi.mall.service.impl;

import com.google.gson.Gson;
import com.xunqi.mall.enums.ProductStatusEnum;
import com.xunqi.mall.enums.ResponseEnum;
import com.xunqi.mall.form.CartAddForm;
import com.xunqi.mall.form.CartUpdateForm;
import com.xunqi.mall.mapper.ProductMapper;
import com.xunqi.mall.pojo.Cart;
import com.xunqi.mall.pojo.Product;
import com.xunqi.mall.service.CartService;
import com.xunqi.mall.vo.CartProductVo;
import com.xunqi.mall.vo.CartVo;
import com.xunqi.mall.vo.ResponseVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Created with IntelliJ IDEA.
 * @author: 夏沫止水
 * @create: 2020-04-24 09:53
 **/
@Slf4j
@Service("cartService")
public class CartServiceImpl implements CartService {

    private final static String CART_REDIS_KEY_TEMPLATE_IMPL = "cart_%d";

    @Resource
    private ProductMapper productMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private Gson gson = new Gson();

    /**
     * 添加商品到购物车
     * @param uid
     * @param form
     * @return
     */
    @Override
    public ResponseVo<CartVo> addCart(Integer uid, CartAddForm form) {

        //添加到购物车里的数量
        Integer quantity = 1;

        //判断商品是否存在
        Product product = productMapper.selectByPrimaryKey(form.getProductId());
        if (product == null) {
            return ResponseVo.error(ResponseEnum.PRODUCT_NOTEXIST);
        }

        //商品是否正常在售状态
        Integer status = product.getStatus();
        if (status.equals(ProductStatusEnum.OFF_SALE) || status.equals(ProductStatusEnum.DELETE)) {
            return ResponseVo.error(ResponseEnum.PRODUCT_OFF_SALE_OR_DELETE);
        }

        //商品库存是否充足
        if (product.getStock() < 0) {
            return ResponseVo.error(ResponseEnum.PRODUCT_NOT_STOCK);
        }

        //将商品信息写入到redis
        HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
        //生成key值
        String cartKey = String.format(CART_REDIS_KEY_TEMPLATE_IMPL, uid);

        //定义一个cart对象
        Cart cart = null;
        //存入到redis之前判断该商品是否存在，若存在商品数量+1，否则就新增一条信息
        String value = opsForHash.get(cartKey, String.valueOf(product.getId()));
        if (value == null) {
            cart = new Cart(product.getId(),quantity,form.getSelected());
        } else {
            //将从redis查询到的数据反序列化成一个cart对象
            cart = gson.fromJson(value, Cart.class);
            cart.setQuantity(cart.getQuantity() + quantity);
        }

        //添加到redis缓存.将cart序列化成一个string字符串类型
        String cartValue = gson.toJson(cart);
        opsForHash.put(cartKey,String.valueOf(product.getId()),cartValue);

        return cartList(uid);
    }


    /**
     * 购物车列表
     * @param uid
     * @return
     */
    @Override
    public ResponseVo<CartVo> cartList(Integer uid) {

        HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
        //生成key值
        String cartKey = String.format(CART_REDIS_KEY_TEMPLATE_IMPL, uid);

        //根据key值获取购物车所有商品信息
        Map<String, String> entries = opsForHash.entries(cartKey);


        List<CartProductVo> cartProductVoList = new ArrayList<>();
        //是否全选
        boolean selectedAll = true;
        //定义总价
        BigDecimal cartTotalPrice = BigDecimal.ZERO;
        //购买的数量
        Integer cartTotalQuantity = 0;

        //取出id集合
        Set<Integer> productIdSet = entries.entrySet().stream()
                .map(e -> Integer.valueOf(e.getKey()))
                .collect(Collectors.toSet());

        //根据id集合查询出多条商品信息
        List<Product> productList = productMapper.selectByProductIdSet(productIdSet);
        //将productList转换成map
        Map<Integer, List<Product>> productMap =
                productList.stream().collect(Collectors.groupingBy(e -> e.getId()));

        CartVo cartVo = null;

        for (Map.Entry<String, String> entry : entries.entrySet()) {
            //获取商品id
            Integer productId = Integer.valueOf(entry.getKey());

            //从map集合中根据key获取商品信息
            Product product = productMap.get(productId).get(0);

            //将value值反序列化为Cart对象
            Cart cart = gson.fromJson(entry.getValue(), Cart.class);

            if (product != null) {
                CartProductVo cartProductVo = CartProductVo.builder()
                        .productId(product.getId())
                        .quantity(cart.getQuantity())
                        .productName(product.getName())
                        .productSubtitle(product.getSubtitle())
                        .productMainImage(product.getMainImage())
                        .productPrice(product.getPrice())
                        .productStatus(product.getStatus())
                        .productTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())))
                        .productStock(product.getStock())
                        .productSelected(cart.getProductSelected())
                        .build();
                cartProductVoList.add(cartProductVo);

                //如果有一个商品未被选中则标记为false
                if (!cart.getProductSelected()) {
                    selectedAll = false;
                }

                //计算全部商品总价格(只计算选中的)
                if (cart.getProductSelected()) {
                    cartTotalPrice = cartTotalPrice.add(cartProductVo.getProductTotalPrice());
                }

                //计算总价
                cartTotalQuantity += cartProductVo.getQuantity();
            }
            //赋值属性
            cartVo = CartVo.builder()
                    .cartProductVoList(cartProductVoList)
                    .selectedAll(selectedAll)
                    .cartTotalPrice(cartTotalPrice)
                    .cartTotalQuantity(cartTotalQuantity)
                    .build();
        }

        return ResponseVo.success(cartVo);
    }

    /**
     * 更新购物车信息
     * @param uid
     * @param productId
     * @param form
     * @return
     */
    @Override
    public ResponseVo<CartVo> updateCart(Integer uid, Integer productId, CartUpdateForm form) {

        HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
        //生成key值
        String cartKey = String.format(CART_REDIS_KEY_TEMPLATE_IMPL, uid);

        //获取数据库商品信息
        Product product = productMapper.selectByPrimaryKey(productId);

        //查询redis是否有该商品
        String value = opsForHash.get(cartKey, String.valueOf(productId));
        if (StringUtils.isEmpty(value)) {
            return ResponseVo.error(ResponseEnum.CART_PRODUCT_NOT_EXIST);
        }

        //已经有了，修改商品信息
        Cart cart = gson.fromJson(value, Cart.class);
        //传过来的商品数量要大于0才能修改
        if (form.getQuantity() != null && form.getQuantity() >= 0) {
            //现有的库存要比你修改的商品数量充足才能修改
            if (product.getStock() >= form.getQuantity()) {
                cart.setQuantity(form.getQuantity());
            } else {
                return ResponseVo.error(ResponseEnum.PRODUCT_NOT_STOCK);
            }
        }

        //商品是否选中
        cart.setProductSelected(form.getSelected());

        //序列化
        String cartValue = gson.toJson(cart);
        opsForHash.put(cartKey,String.valueOf(productId),cartValue);

        return cartList(uid);
    }

    /**
     * 删除购物车某个商品的信息
     * @param uid
     * @param productId
     * @return
     */
    @Override
    public ResponseVo<CartVo> deleteCart(Integer uid, Integer productId) {

        HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
        //生成key值
        String cartKey = String.format(CART_REDIS_KEY_TEMPLATE_IMPL, uid);

        //存入到redis之前判断该商品是否存在，若存在商品数量+1，否则就新增一条信息
        String value = opsForHash.get(cartKey, String.valueOf(productId));
        if (StringUtils.isEmpty(value)) {
            return ResponseVo.error(ResponseEnum.CART_PRODUCT_NOT_EXIST);
        }
        //删除redis数据
        opsForHash.delete(cartKey,String.valueOf(productId));

        return cartList(uid);
    }

    /**
     * 全选中商品
     * @param uid
     * @return
     */
    @Override
    public ResponseVo<CartVo> selectAll(Integer uid) {

        HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
        //生成key值
        String cartKey = String.format(CART_REDIS_KEY_TEMPLATE_IMPL, uid);

        List<Cart> cartList = listForCart(uid);

        for (Cart cart : cartList) {
            cart.setProductSelected(true);
            opsForHash.put(cartKey,String.valueOf(cart.getProductId()),gson.toJson(cart));
        }

        return cartList(uid);
    }

    /**
     * 全不选中商品
     * @param uid
     * @return
     */
    @Override
    public ResponseVo<CartVo> unSelectAll(Integer uid) {

        HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
        //生成key值
        String cartKey = String.format(CART_REDIS_KEY_TEMPLATE_IMPL, uid);

        List<Cart> cartList = listForCart(uid);

        for (Cart cart : cartList) {
            cart.setProductSelected(false);
            opsForHash.put(cartKey,String.valueOf(cart.getProductId()),gson.toJson(cart));
        }

        return cartList(uid);
    }

    /**
     * 查询购物车信息
     * @param uid
     * @return
     */
    @Override
    public List<Cart> listForCart(Integer uid) {

        HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
        //生成key值
        String cartKey = String.format(CART_REDIS_KEY_TEMPLATE_IMPL, uid);

        Map<String, String> entries = opsForHash.entries(cartKey);

        List<Cart> cartList = new ArrayList<>();
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            //获取value值
            String value = entry.getValue();
            Cart cart = gson.fromJson(value, Cart.class);
            cartList.add(cart);
        }

        return cartList;
    }

    /**
     * 获取购物中所有商品数量总和
     * @param uid
     * @return
     */
    @Override
    public ResponseVo sumCart(Integer uid) {

        //获取购物车里的商品
        List<Cart> cartList = listForCart(uid);

        // //进行商品数量的累加
        // Integer sum = cartList.stream().map(e -> e.getQuantity())
        //         .reduce(0, Integer::sum);

        Integer sum = 0;
        for (Cart cart : cartList) {
            sum += cart.getQuantity();
        }
        return ResponseVo.success(sum);
    }
}
